﻿using System;
using System.Collections.Generic;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;

namespace Gmantis.Controls
{
    internal abstract class MenuItemBehavior
    {
        // Fields
        private bool _popupLoaded;

        // Methods
        public MenuItemBehavior(MenuItem item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }
            this.MenuItem = item;
        }

        public abstract MenuItem GetFirstItem();
        public abstract MenuItem GetLastItem();
        public MenuItem GetNextEnabledItem(IList<MenuItem> items, int start)
        {
            for (int i = Math.Max(start, 0); i < items.Count; i++)
            {
                if (items[i].IsEnabled)
                {
                    return items[i];
                }
            }
            for (int j = 0; j < start; j++)
            {
                if (items[j].IsEnabled)
                {
                    return items[j];
                }
            }
            return null;
        }

        public abstract MenuItem GetNextItem(Orientation orientation);
        public virtual List<AnchorMatching> GetPreferedLocations()
        {
            List<AnchorMatching> list = new List<AnchorMatching>();
            AnchorMatching item = new AnchorMatching
            {
                FixedElementAnchor = Anchor.TopRight,
                MoveableElementAnchor = Anchor.TopLeft
            };
            list.Add(item);
            AnchorMatching matching2 = new AnchorMatching
            {
                FixedElementAnchor = Anchor.TopLeft,
                MoveableElementAnchor = Anchor.TopRight
            };
            list.Add(matching2);
            AnchorMatching matching3 = new AnchorMatching
            {
                FixedElementAnchor = Anchor.BottomRight,
                MoveableElementAnchor = Anchor.BottomLeft
            };
            list.Add(matching3);
            AnchorMatching matching4 = new AnchorMatching
            {
                FixedElementAnchor = Anchor.BottomLeft,
                MoveableElementAnchor = Anchor.BottomRight
            };
            list.Add(matching4);
            AnchorMatching matching5 = new AnchorMatching
            {
                FixedElementAnchor = Anchor.TopRight,
                MoveableElementAnchor = Anchor.TopLeft
            };
            list.Add(matching5);
            return list;
        }

        public MenuItem GetPrevEnabledItem(IList<MenuItem> items, int start)
        {
            for (int i = Math.Min(start, items.Count - 1); i >= 0; i--)
            {
                if (items[i].IsEnabled)
                {
                    return items[i];
                }
            }
            for (int j = items.Count - 1; j > start; j--)
            {
                if (items[j].IsEnabled)
                {
                    return items[j];
                }
            }
            return null;
        }

        public abstract MenuItem GetPrevItem(Orientation orientation);
        public virtual MenuItem HandleKey(Key key)
        {
            MenuItem menuItem = this.MenuItem;
            switch (key)
            {
                case Key.End:
                    return this.GetLastItem();

                case Key.Home:
                    return this.GetFirstItem();

                case Key.Left:
                    return this.GetPrevItem(Orientation.Horizontal);

                case Key.Up:
                    return this.GetPrevItem(Orientation.Vertical);

                case Key.Right:
                    return this.GetNextItem(Orientation.Horizontal);

                case Key.Down:
                    return this.GetNextItem(Orientation.Vertical);
            }
            return menuItem;
        }

        public virtual void MakeRelative(Popup popup)
        {
            popup.MakeRelative(this.MenuItem, new Func<List<AnchorMatching>>(this.GetPreferedLocations), false);
        }

        public abstract void OnMouseClick(object sender, MouseEventArgs e);
        public abstract void OnMouseEnter(object sender, MouseEventArgs e);
        public abstract void OnMouseLeave(object sender, MouseEventArgs e);
        public void ResetIsSubmenuOpenVisuals(MenuItem menuItem)
        {
            foreach (MenuItem item in menuItem.GetParentContainers<MenuItem>())
            {
                if (item != this.MenuItem)
                {
                    item.IsSubmenuOpenVisual = false;
                    if (item.IsSubmenuOpen)
                    {
                        foreach (MenuItem item2 in item.MenuItems)
                        {
                            this.ResetIsSubmenuOpenVisuals(item2);
                        }
                    }
                }
                else if (this.MenuItem.IsSubmenuOpen)
                {
                    menuItem.IsSubmenuOpenVisual = true;
                }
            }
        }

        public virtual void ShowSubItems()
        {
            Action action = null;
            if (this._popupLoaded)
            {
                this.MenuItem._elementSubItemsPopup.IsOpen = true;
            }
            else
            {
                if (action == null)
                {
                    action = delegate
                    {
                        this._popupLoaded = true;
                        this.MenuItem._elementSubItemsPopup.IsOpen = true;
                    };
                }
                this.MenuItem._elementSubItemsPopup.BeginInvoke(action);
            }
        }

        // Properties
        public MenuItem MenuItem { get; set; }
    }
}
